#include <length.h>
#include <structure.h>
#include <MM/MM.h>
#include <BasicMatic.h>

#include "IFD.h"
#include "IFDInterface.h"

using namespace IFDInterface;


using namespace IFD;
  memBlocks buffers(bufferStart,bufferEnd,PAGE_SIZE);

  //Too complicated
  FRESULT BufferSync(ibuffs* _buffers,_ptlong* from,const _length& num,const _length& offset)
  {//Edit the Covered place
	//It's delayed. Divide
    _ptlong pagenum = ((num % PAGE_SIZE == 0)? (num / PAGE_SIZE) : (num /PAGE_SIZE + 1)); 
    _ptlong addr = (_ptlong)buffers.PopGroup(pagenum);
    ibuff newbuff(offset,offset+num,(_ptlong*)addr);
    ibuffs::iterator it;
    while((it = _buffers->find(newbuff))!= _buffers->end())
      {//shot down!,Just Remove
	if(!((newbuff.end >= (*it).end) && (newbuff.begin <= (*it).begin)))
	  {
	    if(newbuff.end + 1 < (*it).end)
	      _buffers->insert(ibuff(newbuff.end+1,(*it).end,(_ptlong)(((*it).addr)) + newbuff.end - (*it).begin + 1));
	    if(newbuff.begin -1 > (*it).begin)
	      _buffers->insert(ibuff((*it).begin,newbuff.begin - 1,((_ptlong)((*it).addr)) + newbuff.begin - 1 - (*it).begin));
	  }
	_buffers->erase(it);
	//	buffers.insert(newbuff);
      }
    _buffers->insert(newbuff);
    for(_ptlong i = 0 ; i < pagenum ; i+=1,addr += PAGE_SIZE)
      PushBufferMemory((_ptlong*)addr);
  }

#define ERROR_RET(x)  if((ret = (x))!= FR_OK) return ret
  
template<typename T>
FRESULT BufferGet(ibuffs* _buffers,_ptlong* to,const _length& num,const _length& offset,T read)
  {//read from buffers  and (*read)  to 'to', sync the buffers
    //FRESULT (*read)(_length,_length,_ptlong*)
    ibuff getbuff(offset,offset+num,NULL);
    _length _readoffset = offset;
    _ptlong readptr = to;
    ibuffs::iterator it;
    FRESULT ret;
    while((it = _buffers->find(getbuff)) != _buffers->end())
      {
	if(_readoffset != (*it).begin)
	  {
	    ERROR_RET(read((*it).begin - _readoffset,_readoffset,readptr));
	    ERROR_RET(BufferSync(_buffers,(_ptlong*)readptr,(*it).begin - _readoffset,_readoffset));
	    readptr += (*it).begin - _readoffset;
	    _readoffset += (*it).begin - _readoffset;
	  }
	ERROR_RET(ReadBuffer((*it).addr,readptr,(*it).end - (*it).begin + 1,_readoffset,read));
	readptr += (*it).end - (*it).begin + 1;
	_readoffset += (*it).end - (*it).begin + 1;
      }
    if(_readoffset != offset + num)
      {
	ERROR_RET(read(offset + num - _readoffset,_readoffset,readptr));
      }
  }



#define PAGE_ALIGN(x)   (x & (1 << 12))
#define PAGE_OFFSET(x)  (x & ((~0) << 12))
template<typename T>
static FRESULT ReadBuffer(_ptlong from,_ptlong to,const _length& num,const _length& offset,T read)
{
  _length readamount = 0;
  while(readamount < num)
    {
      _ptlong _readamount = PAGE_SIZE - PAGE_OFFSET(from); 
      _ptlong ret;
      if(((CheckBufferMemoryValidThen(NOW,from,[&]()->void{_Memcpy(from,to,_readamount);ret = 1;})),ret != 1))
	{
	  read((_readamount),offset,to);
	}
      

      to += _readamount;
      readamount += _readamount; 
      from += _readamount;
	  
    }
}

